#lang web-server/insta
(struct blog (posts) #:mutable)

(struct post (title body comments) #:mutable)

(define BLOG
  (blog
   (list (post "First Post"
               "This is my first post"
               (list "First comment!"))
         (post "Second Post"
               "This is another post"
               (list)))))

(define (blog-insert-post! a-blog a-post)
  (set-blog-posts! a-blog
                   (cons a-post (blog-posts a-blog))))

(define (post-insert-comment! a-post a-comment)
  (set-post-comments!
   a-post
   (append (post-comments a-post) (list a-comment))))

(define (start request)
  (render-blog-page request))

(define (render-blog-page request)
  (local [(define (response-generator make-url)
            (response/xexpr
             `(html (head (title "My Blog"))
                    (body
                     (h1 "My Blog")
                     ,(render-posts make-url)
                     (form ((action
                             ,(make-url insert-post-handler)))
                           (input ((name "title")))
                           (input ((name "body")))
                           (input ((type "submit"))))))))
          (define (parse-post bindings)
            (post (extract-binding/single 'title bindings)
                  (extract-binding/single 'body bindings)
                  (list)))
          
          (define (insert-post-handler request)
            (blog-insert-post!
             BLOG (parse-post (request-bindings request)))
            (render-blog-page request))]
    
    (send/suspend/dispatch response-generator)))

(define (render-post-detail-page a-post request)
  (local [(define (response-generator make-url)
            (response/xexpr
             `(html (head (title "Post Details"))
                    (body
                     (h1 "Post Details")
                     (h2 ,(post-title a-post))
                     (p ,(post-body a-post))
                     ,(render-as-itemized-list
                       (post-comments a-post))
                     (form ((action
                             ,(make-url insert-comment-handler)))
                           (input ((name "comment")))
                           (input ((type "submit"))))))))
          
          (define (parse-comment bindings)
            (extract-binding/single 'comment bindings))
          
          (define (insert-comment-handler a-request)
            (post-insert-comment!
             a-post (parse-comment (request-bindings a-request)))
            (render-post-detail-page a-post a-request))]
    
    (send/suspend/dispatch response-generator)))

(define (render-post a-post make-url)
  (local [(define (view-post-handler request)
            (render-post-detail-page a-post request))]
    `(div ((class "post"))
          (a ((href, (make-url view-post-handler)))
             ,(post-title a-post))
          (p, (post-body a-post))
          (div, (number->string (length (post-comments a-post)))
              " comments(s)"))))

(define (render-posts make-url)
  (local [(define (render-post/make-url a-post)
            (render-post a-post make-url))]
    `(div ((class "posts"))
          ,@(map render-post/make-url (blog-posts BLOG)))))

(define (render-as-itemized-list fragments)
  `(ul ,@(map render-as-item fragments)))

(define (render-as-item a-fragment)
  `(li ,a-fragment))
